package com.synjones.bluetoothInterface;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;

import com.synjones.idcard.IDCardReaderRetInfo;
import com.synjones.idcard.IDcardReader;
import com.synjones.multireaderlib.CmdResponse;
import com.synjones.multireaderlib.DataTransInterface;
import com.synjones.multireaderlib.IOProtocol.ProtocolType;
import com.synjones.multireaderlib.MultiReader;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.DatabaseErrorHandler;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

public class BluetoothReader implements DataTransInterface{

	public static final int MESSAGE_CONNECTING_DEVICE=0xa1;
	public static final int MESSAGE_DISCONNECTED=0xa2;
	public static final int MESSAGE_CONNECTED=0xa3;
	public static final int CANCEL_SELECT_DEVICE=11;
	public static final int CONNECT_BT_DEVICE = 10;
	public static final String ACTION_STATUS="com.synjones.bluethooth.action.readerstatus";
	public static final String STATUS="status";
	public static final String STATUS_CODE="status_code";
	public MultiReader baseReader=MultiReader.getReader();
	public IDcardReader idcardReader;
	
	private BluetoothAdapter bluetoothAdapter;
	private Activity activity;
	private Context mContext;
	private String currentMAC = "";
	private OutputStream mFileOutputStream;
	private InputStream mFileInputStream;
	private BroadcastReceiver myBtPairReceiver;
	private FragmentManager fragManager;
	private boolean isReaderConnect=false;
	private ConnectThread ct;
	
	Handler insideHandler=new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case CONNECT_BT_DEVICE:
				String MAC = (String) msg.obj;
				currentMAC = MAC;		//暂存MAC，重启使用
				BluetoothDevice device = bluetoothAdapter.getRemoteDevice(MAC);
				ct=new ConnectThread(device);
				ct.start();
				break;
			case CANCEL_SELECT_DEVICE:
				//mHandler.obtainMessage(MESSAGE_DISCONNECTED).sendToTarget();
				sendReaderBroadcast(MESSAGE_DISCONNECTED,"用户取消连接");
				break;
			default:
				break;
			}						
		};
	};
	/**
	 * 可使用以下两种方式连接蓝牙：<br>
	 * @方式1 由此程序负责蓝牙连接，需调用initBtConnect初始化蓝牙连接并注册广播接收状态
	 * @方式2 由你负责蓝牙连接（可参考此程序连接蓝牙），连接到读卡器蓝牙后，需调用setIOStream设置数据输入输出流。
	 */
	public BluetoothReader(Context mContext){
		baseReader.setDataTransInterface(this);
		idcardReader=new IDcardReader(baseReader);
		//this.activity=act;
		this.mContext=mContext;
	}
	/**
	 * 初始化蓝牙连接，然后调用connectBtReader连接读卡器
	* @Title initBtConnect 
	* @param activity
	 */
	public void initBtConnect(Activity activity){
		this.activity = activity;
		this.fragManager = activity.getFragmentManager();
		bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
		myBtPairReceiver=new BluetoothConnectActivityReceiver();

	}
	
	/**
	 * 设置读卡器的数据输入输出接口，之后需要调用open打开读卡器
	* @Title setIOStream 
	* @param inputStream
	* @param outputStream
	* @see open
	 */
	public void setIOStream(InputStream inputStream,OutputStream outputStream){
		this.mFileInputStream=inputStream;
		this.mFileOutputStream=outputStream;
	}
	
	/**
	 * 打开读卡器，此函数会阻塞当前线程。使用@see close关闭读卡器
	* @Title open 
	* @param timeout 等待超时
	* @return
	* @see close
	 */
	public boolean open(long timeout){
		idcardReader.open(mContext);
	//	baseReader.EnterWorkMode(0);
       // mySleep(800);
        long startTime=System.currentTimeMillis();
        while(System.currentTimeMillis()-startTime<timeout){
        	CmdResponse ret=idcardReader.findIDCard();
        	if(true) {//通信ok
        		 isReaderConnect=true;
        		 saveBtinfo();
        		 sendReaderBroadcast(MESSAGE_CONNECTED,"连接成功");
        		 return true;
        	}
        	mySleep(100);
        }
        disconnect("连接超时");
        return false;
	}
	/**
	 * 关闭读卡器
	* @Title close
	 */
	public void close(){
		try {
			idcardReader.close();
		} catch (Exception e) {}
		try {
			baseReader.EnterSavePowerMode(0);
		} catch (Exception e) {}
	
	}
	
	/**
	 * 读二代证，此函数会阻塞当前线程
	* @Title read 
	* @return
	 */
	public IDCardReaderRetInfo read(){
		//每张卡片可重复读取，解码照片，不读取指纹信息
		IDCardReaderRetInfo ret = idcardReader.getIDcardBlockingNoFpRetInfo(false);
		/*
		 *
		下面的函数和idcardReader.getIDcardBlockingNoFpRetInfo(false)功能一样
		IDCardReaderRetInfo ret = idcardReader.getIDCardInfo(false, true, false);
		
		 获取指纹信息
		IDCardReaderRetInfo ret = idcardReader.getIDCardInfo(false, true, true);
		
		每张卡片只读一次，但是底层程序可能不支持
		IDCardReaderRetInfo ret = idcardReader.getIDCardInfo(true, true, true);
		*/
		return ret;
	}
	
	
	/**
	 * 读二代证，此函数会阻塞当前线程
	* @Title read 
	* @return
	 */
	public IDCardReaderRetInfo read(int retranseTime){
		IDCardReaderRetInfo ret = idcardReader.getIDcardBlockingNoFpRetInfo(false);
		if(ret.errCode==IDCardReaderRetInfo.ERROR_RECV_FINDCARD){
			ret = idcardReader.getIDcardBlockingNoFpRetInfo(false);
		}
		if(retranseTime>0){
			while (ret.errCode==IDCardReaderRetInfo.ERROR_RECV_READBASE && retranseTime>0) {
				ret=idcardReader.getLastBaseMsg(false);
				retranseTime--;
			}
		}
		return ret;
	}
	/**
	 * 获取读卡器电量，此函数会阻塞当前线程
	* @Title getBatteryPercent 
	* @return
	 */
	public int getBatteryPercent(){
		byte tmp[]=baseReader.getBatteryInfo();
		if(tmp==null) return -1;
		int input=((tmp[0]<<8)&0xff00)|(tmp[1]&0xff);
		BigDecimal binput=new BigDecimal(input);
		BigDecimal factor=new BigDecimal("0.001220703125");//通过分压电阻的电压计算电池电压 10/4096
		binput=binput.multiply(factor);
		//String volt=binput.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString();
		binput=binput.subtract(new BigDecimal(3.4));//以3.4V为起点，以4.2为终点，计算电池百分比电量
		
		int batteryVoltPercent=0;
		if(binput.compareTo(new BigDecimal("0"))>0){
			binput=binput.divide(new BigDecimal(0.8),2,BigDecimal.ROUND_HALF_EVEN);//4.2-3.4
			binput=binput.multiply(new BigDecimal("100"));
			batteryVoltPercent=	binput.intValue();
		}
		if(batteryVoltPercent>100)
			batteryVoltPercent=100;
		if(batteryVoltPercent<0)
			batteryVoltPercent=0;
		return batteryVoltPercent;
	}
	
	private boolean setIDModulePowerStatus(int onOffStaus){
		CmdResponse res=baseReader.setIdModulePara(MultiReader.SET_MODULE_STATUS, onOffStaus);
		if(res!=null && res.SwIs9000())
			return true;
		return false;
	}
	
	private byte getIDModulePowerStatus(){
		CmdResponse res=baseReader.getIdModulePara(MultiReader.GET_MODULE_STATUS);
		if( res==null ||!res.SwIs9000())
			return -1;
		try {
			return res.getCommonData()[1];
		} catch (Exception e) {}
		return -1;
	}
	
	public boolean isModulePowerUp(){
		return getIDModulePowerStatus()==0;
	}
	
	public boolean setModulePowerUp(boolean on){
		int para=on?MultiReader.MODULE_STATUS_ON:MultiReader.MODULE_STATUS_OFF;
		return setIDModulePowerStatus(para);
	}
	
	//不支持注释的命令
	/*
	public boolean setBtPacketLen(int len){
		return setBtTransPara(MultiReader.SET_PACKET_LENGTH, len);
	}
	
	public boolean setBtPacketDelay(int delay){
		return setBtTransPara(MultiReader.SET_PACKET_DELAY, delay);
	}
	
	public int getBtPacketLen(){
		return getBtTransPara(MultiReader.GET_PACKET_LENGTH)&0xff;
	}
	
	public int getBtPacketDelay(){
		return getBtTransPara(MultiReader.GET_PACKET_DELAY)&0xff;
	}
	
	
	private boolean setBtTransPara(int cmd,int para ){
		CmdResponse res=baseReader.setBtTransPara(cmd, para);
		if(res!=null && res.SwIs9000())
			return true;
		return false;
	}
	
	private byte getBtTransPara(int paraNo ){
		CmdResponse res=baseReader.getBtTransPara(paraNo);
		if(res ==null || !res.SwIs9000())
			return -1;
		try {
			return res.getCommonData()[1];
		} catch (Exception e) {}
		return -1;
		
	}*/

	
	/**
	 * 获取二代证模块编号，此函数会阻塞当前线程
	* @Title getSamvID 
	* @return
	 */
	public String getSamvID(){
		return idcardReader.getSamvIDStr();
	}
	
	/**
	 * 打开蓝牙，连接读卡器
	* @Title connectBtReader
	 */
	public void connectBtReader() {
		// btnReadCardOpenStop.setEnabled(false);
		if (bluetoothAdapter == null){
			sendReaderBroadcast(MESSAGE_DISCONNECTED, "获取蓝牙适配器失败");
			return;
		}
		
		if(isReaderConnect){//重新连接
			disconnect("正在重连");
			mySleep(1000);
			BluetoothDevice device = bluetoothAdapter.getRemoteDevice(currentMAC);
			ct=new ConnectThread(device);
			ct.start();
			return ;
		}
		
	
		if (bluetoothAdapter.isEnabled()) {
			selectDevice();
		} else {

			Fragment f = new Fragment() {
				private static final int REQUEST_ENABLE_BT = 2;
                @Override
                public void onAttach(Activity activity) {
                    super.onAttach(activity);
        			Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                    startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BT);
                }
                @Override
                public void onActivityResult(int requestCode, int resultCode,
                		Intent data) {
                	switch (requestCode) {
            		case REQUEST_ENABLE_BT:
            			if (resultCode == Activity.RESULT_OK) {
            				selectDevice();
            			} else {
            				Toast.makeText(activity, "启动蓝牙不成功", Toast.LENGTH_SHORT).show();
            				activity.finish();
            			}
            			break;
            		}
                	super.onActivityResult(requestCode, resultCode, data);
                }


            };
            FragmentTransaction fragmentTransaction = this.fragManager.beginTransaction();
            fragmentTransaction.add(f, "getusername");
            fragmentTransaction.commit();
		}		
	}
	
	
	/**
	 * 断开读卡器蓝牙连接
	* @Title disconnect
	 */
	public void disconnect(String reason) {
		// TODO Auto-generated method stub
		try {
			isReaderConnect=false;
			close();
			ct.cancel(reason);
		} catch (Exception e) {}
		
	}
	
	
	private void sendReaderBroadcast(int statusCode,String msg){
		Intent intent=new Intent(ACTION_STATUS);
		intent.putExtra(STATUS, msg);
		intent.putExtra(STATUS_CODE, statusCode);
		mContext.sendBroadcast(intent);
	}


	
	void selectDevice() {
		Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
		new GetBtDevicesListView(activity, pairedDevices, new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				if(!bluetoothAdapter.startDiscovery()) return;
				final ProgressDialog pd=ProgressDialog.show(activity, "", "正在搜索", true, true);
				insideHandler.postDelayed(new Runnable(
						) {
					@Override
					public void run() {
						try {
							bluetoothAdapter.cancelDiscovery();
							pd.dismiss();
						} catch (Exception e) {
						}
					}
				}, 12000);
			}	
		},insideHandler);
	}

	
	
	
	/**
	 * 释放读卡器资源
	* @Title release
	 */
	public void release() {
		// TODO Auto-generated method stub
		try {
			disconnect("断开连接");
			activity.unregisterReceiver(myBtPairReceiver);
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}


	private void saveBtinfo(){
		try {
			if(currentMAC.isEmpty()) return ;
			BluetoothDevice device = bluetoothAdapter.getRemoteDevice(currentMAC);
			SharedPreferences sp=mContext.getSharedPreferences("btconfig", Context.MODE_PRIVATE);
			sp.edit().putString("syn_dev_Name", device.getName()).commit();
			sp.edit().putString("syn_dev_Mac", device.getAddress()).commit();
		} catch (Exception e) {}
	}

	public boolean isConnect() {
		// TODO Auto-generated method stub
		return isReaderConnect;
	}

	private class ConnectThread extends Thread {
	    private final BluetoothSocket mmSocket;
	    private final BluetoothDevice mmDevice;
	 
	    public ConnectThread(BluetoothDevice device) {
	        // Use a temporary object that is later assigned to mmSocket,
	        // because mmSocket is final
		//	IntentFilter filter = new IntentFilter("android.bluetooth.device.action.PAIRING_REQUEST");
		//	filter.setPriority(Integer.MAX_VALUE); 
	   // 	activity.registerReceiver(myBtPairReceiver,filter);
	    	sendReaderBroadcast(MESSAGE_CONNECTING_DEVICE,"正在连接");
	        BluetoothSocket tmp = null;
	        mmDevice = device;
	 
	        // Get a BluetoothSocket to connect with the given BluetoothDevice
	        try {
	            // MY_UUID is the app's UUID string, also used by the server code
	            tmp = device.createRfcommSocketToServiceRecord(UUID
						.fromString("00001101-0000-1000-8000-00805F9B34FB"));
	        } catch (IOException e) { }
	        mmSocket = tmp;
	    }
	 
	    public void run() {
	        // Cancel discovery because it will slow down the connection
	    	bluetoothAdapter.cancelDiscovery();
	 
	        try {
	            // Connect the device through the socket. This will block
	            // until it succeeds or throws an exception
	            mmSocket.connect();
	            mFileInputStream = mmSocket.getInputStream();
				mFileOutputStream = mmSocket.getOutputStream();
	        } catch (Exception connectException) {
	            // Unable to connect; close the socket and get out
	        	cancel(connectException.getMessage());
	            return;
	        }
	     //   activity.unregisterReceiver(myBtPairReceiver);
	        new Thread(new RecvThread()).start();
	        open(3000);
	        // Do work to manage the connection (in a separate thread)
	      
	        
	    }
	 
	    /** Will cancel an in-progress connection, and close the socket */
	    public void cancel(String reason) {
	    	recvRunFlag=false;
	    	try {
		    	if (mFileInputStream!= null) {
					mFileInputStream.close();
					mFileInputStream = null;
				}
			} catch (Exception e) {}

	    	try {
	    		if (mFileOutputStream != null) {
					mFileOutputStream.close();
					mFileOutputStream = null;
				}
			} catch (Exception e) {}
			
	        try {
	            mmSocket.close();
	        } catch (Exception e) { }
	        sendReaderBroadcast(MESSAGE_DISCONNECTED,""+reason);
	    }
	    
	}	
	
	public void mySleep(long time){
		try {
			Thread.sleep(time);
		} catch (Exception e) {}
	}
	
	@Override
	public void sendData(byte[] data, int datalen) {
		// TODO Auto-generated method stub
		try {
			mFileOutputStream.write(data, 0, datalen);
			mFileOutputStream.flush();
		//	Log.e("sendData", "write len="+datalen);
		}catch (IOException ioe) {
			ioe.printStackTrace();
		}catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	@Override
	public int recvData(byte[] recvbuf, int offset) {
		// TODO Auto-generated method stub
		try {
			if(recvWay==RecvWay.DirectRead){//非阻塞 直接读
				if(mFileInputStream.available()>0){
					int len=mFileInputStream.read(recvbuf, offset, recvbuf.length-offset);
					//Log.e("btRecv", util.bytesToHexString(recvbuf, offset+len));
					return len;
				}
			}
			else{
				int size=iReadQueueArray.size();
				if(size<=0) return 0;
				Thread.sleep(20);
			//	synchronized (ReadQueueLock) {
					int retLen=(recvbuf.length-offset)>iReadQueueArray.size()?iReadQueueArray.size():(recvbuf.length-offset);
					for(int i=0;i<retLen;i++)
						recvbuf[i+offset]=iReadQueueArray.poll();
					return retLen;
			//	}
			}
			
		//}catch (IOException ioe) {
		//	ioe.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}

	@Override
	public void clear() {
		// TODO Auto-generated method stub
		try {
			if(recvWay==RecvWay.ThreadRead){
				//synchronized (ReadQueueLock) {
					iReadQueueArray.clear();
				//}
			}
			else{
				while(mFileInputStream.available()>0){
					byte buffer[]=new byte[1024];
					mFileInputStream.read(buffer);
				}
			}
		//}catch (IOException ioe) {
		//	ioe.printStackTrace();
		}catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	private  boolean recvRunFlag=false;
	private ArrayBlockingQueue<Byte> iReadQueueArray = new ArrayBlockingQueue<Byte>(10240, true);
	public enum RecvWay{DirectRead,ThreadRead};
	private RecvWay recvWay=RecvWay.ThreadRead;
	public void setRecvWay(RecvWay way){this.recvWay=way;}
	
	private class RecvThread implements Runnable{
		public void run(){
			recvRunFlag=true;
			Log.e("btRecv", "recv Thread start!");
			
			if(recvWay==RecvWay.DirectRead){
				//测试蓝牙socket是不是阻塞的
				long cut=System.currentTimeMillis();
				try {
					mFileInputStream.available();//有些手机的此方法可能会阻塞
				} catch (Exception e1) {
					e1.printStackTrace();
				}
				if(System.currentTimeMillis()-cut>100){
					//超时，使用线程读的效果可能好点
					recvWay=RecvWay.ThreadRead;
				}
			}
			
			if(recvWay==RecvWay.DirectRead){
				recvRunFlag=false;
			}
			
			Log.e("btRecv", "RecvWay:"+recvWay);
			
			byte buffer[]=new byte[1024];
			while(recvRunFlag){
				//isSocketBlockMode=true;
				int readlen=0;
				try {
					readlen=mFileInputStream.read(buffer);
				} catch (Exception e) {	
					//readlen=-1;
					e.printStackTrace();
					if(recvRunFlag)
						disconnect(""+e.getMessage());
					break;
				}
				if(readlen>0){
					//synchronized (ReadQueueLock) {
						int i=0;
						while(iReadQueueArray.size()<10240 && i<readlen){
							try {
								iReadQueueArray.offer(buffer[i++]);
							} catch (Exception e) {
								e.printStackTrace();
								break;
							}
						}
					//}
					//Log.e("btRecv", util.bytesToHexString(buffer, readlen));
				}
			}
			Log.e("btRecv", "recv Thread quit!!");
		}
	}
	
	
	
	
}
